package com.apes.framework.plugin.form.parser.matcher;

import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.model.Filter;
import com.apes.framework.jpa.spec.model.Group;
import com.apes.framework.util.Operation;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;

/**
 * 功能：波兰表达式模式匹配器
 *
 * @author xul
 * @create 2018-04-19 15:04
 */
public class PolishMatcher implements Matcher<String, Object> {

    private Matcher parent;

    /**
     * 功能：获取识别模式
     */
    @Override
    public String getRegex() {
        return "(\\[)(.+?)(\\])";
    }

    @Override
    public Matcher getParent() {
        return parent;
    }

    @Override
    public void setParent(Matcher parent) {
        this.parent = parent;
    }


    /**
     * 功能：模式配置
     *
     * @param content
     */
    @Override
//    @Timer("解析波兰表达式")
    public Object parse(String content) {
        Pattern pattern = Pattern.compile(getRegex());
        java.util.regex.Matcher matcher = pattern.matcher(content);
        String conditional = null;
        while (matcher.find()) {
            conditional = matcher.group(2).trim();
        }
        return matcher(conditional);
    }

    /**
     * 实现calculate函数，来计算逆波兰表达式，
     *
     * @param pn 波兰表达式字符串
     * @return 结果字符串
     */
    public Object matcher(String pn) {
        List<String> items = parsePn(pn);
        Stack<Object> stack = new Stack();
        Object one = null, two = null;
        for (Object item : items) {
            boolean isOperation = false;
            if (item instanceof String) isOperation = Operation.isLogicOperation((String) item);
            if (isOperation) {
                if (item.equals("&") || item.equals("|") || item.equals("and") || item.equals("or")) {
                    if (stack.size() < 2) throw new RuntimeException("表达式：" + pn + "输入错误！");
                    one = stack.pop();
                    two = stack.pop();
                } else if (item.equals("!")) {
                    one = stack.pop();
                } else {
                    throw new RuntimeException("操作运算符：" + item + " 不支持！");
                }
            }

            if (item.equals("&") || item.equals("and")) {
                if (one instanceof Group || one instanceof Filter) {
                    one = setGroup("and", one, two);
                } else {
                    one = "(" + one + " " + Operation.getTsType((String) item) + " " + two + ")";
                }
                stack.push(one);
            } else if (item.equals("|") || item.equals("or")) {
                if (one instanceof Group || one instanceof Filter) {
                    one = setGroup("or", one, two);
                } else {
                    one = "(" + one + " " + Operation.getTsType((String) item) + " " + two + ")";
                }
                stack.push(one);
            } else if (item.equals("!")) {
                one = "(" + Operation.getTsType((String) item) + "" + one + ")";
                stack.push(one);
            } else {
                stack.push(item);
            }
        }

        if (stack.size() != 1) throw new RuntimeException("表达式输入错误！");
        one = stack.pop();
        if(one instanceof Filter){
            Group group = new Group();
            group.addFilter((Filter) one);
            one = group;
        }
        return one;
    }

    private Group setGroup(String operator, Object one, Object two) {
        Group group = one instanceof Group ? (Group) one : new Group().setOperator(operator);
        if (!group.getOperator().equalsIgnoreCase(operator)) {
            Group temp = group;
            group = new Group().setOperator(operator).addGroup(temp);
        }
        if (one instanceof Filter) group.addFilter((Filter) one);
        group.addFilter((Filter) two);
        return group;
    }


    /**
     * 解析传入的波兰表达式，区分出操作数与操作符
     *
     * @param pn 波兰表达式字符串
     * @return 解析后的字符串列表
     */
    private List parsePn(String pn) {
        ParenthesesMatcher parenthesesMatcher = new ParenthesesMatcher();
        parenthesesMatcher.setParent(this);
        List result = parenthesesMatcher.parse(pn);
        OperationMatcher operationMatcher = new OperationMatcher();
        operationMatcher.setParent(this);
        List<String> operations = operationMatcher.parse(pn);
        Collections.reverse(result);
        result.addAll(operations);
        return result;
    }


}
